using CfgTable;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class UIQuest : UIBaseWindow
    {
        /// <summary>
        /// 静态配置
        /// </summary>
        private static UICreateConfig _createConfig = new()
        {
            prefabName = nameof(UIQuest),
            layer = EUILayer.Normal,
            isFullScreen = true,
        };

        /// <summary>
        /// 创建UI的配置
        /// </summary>
        public override IUICreateConfig createConfig => _createConfig;

        #region Template Generate,don't modify

        protected partial class UIB_UIQuest
        {
            #region ObjectBinding Generate
            public UnityEngine.GameObject topLeftBack { protected set; get; }
            public UnityEngine.GameObject toggleTab { protected set; get; }
            public UnityEngine.UI.ExLoopVerticalScrollRect loopVerticalScrollRect { protected set; get; }
            public UnityEngine.GameObject panelInfo { protected set; get; }
            public IQIGame.Onigao.Framework.ExText textName { protected set; get; }
            public IQIGame.Onigao.Framework.ExText textLocation { protected set; get; }
            public IQIGame.Onigao.Framework.ExText textDesc { protected set; get; }
            public UnityEngine.UI.ExLoopVerticalScrollRect targetScroll { protected set; get; }
            public UnityEngine.GameObject commonItem { protected set; get; }
            public IQIGame.Onigao.Framework.ExButton btnConfirm { protected set; get; }
            public UnityEngine.GameObject empty { protected set; get; }
            public UnityEngine.GameObject costMoney { protected set; get; }
            public IQIGame.Onigao.Framework.ExButton btnTrack { protected set; get; }
            public IQIGame.Onigao.Framework.ExButton btnCacelTrack { protected set; get; }
            public UnityEngine.GameObject location { protected set; get; }
            public UnityEngine.GameObject locationValue { protected set; get; }
            public virtual void InitBinding(ObjectBinding __binding)
            {
                __binding.TryGetVariableValue<UnityEngine.GameObject>("topLeftBack", out var __tbv0);
                this.topLeftBack = __tbv0;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("toggleTab", out var __tbv1);
                this.toggleTab = __tbv1;
                __binding.TryGetVariableValue<UnityEngine.UI.ExLoopVerticalScrollRect>("loopVerticalScrollRect", out var __tbv2);
                this.loopVerticalScrollRect = __tbv2;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("panelInfo", out var __tbv3);
                this.panelInfo = __tbv3;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExText>("textName", out var __tbv4);
                this.textName = __tbv4;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExText>("textLocation", out var __tbv5);
                this.textLocation = __tbv5;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExText>("textDesc", out var __tbv6);
                this.textDesc = __tbv6;
                __binding.TryGetVariableValue<UnityEngine.UI.ExLoopVerticalScrollRect>("targetScroll", out var __tbv7);
                this.targetScroll = __tbv7;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("commonItem", out var __tbv8);
                this.commonItem = __tbv8;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExButton>("btnConfirm", out var __tbv9);
                this.btnConfirm = __tbv9;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("empty", out var __tbv10);
                this.empty = __tbv10;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("costMoney", out var __tbv11);
                this.costMoney = __tbv11;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExButton>("btnTrack", out var __tbv12);
                this.btnTrack = __tbv12;
                __binding.TryGetVariableValue<IQIGame.Onigao.Framework.ExButton>("btnCacelTrack", out var __tbv13);
                this.btnCacelTrack = __tbv13;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("location", out var __tbv14);
                this.location = __tbv14;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("locationValue", out var __tbv15);
                this.locationValue = __tbv15;
            }
            #endregion ObjectBinding Generate
        }

        #endregion Template Generate,don't modify

        #region fields & properties
        private ListScrollAdapter<UIN_QuestTab> tabs = null;
        private ListScrollAdapter<UIN_OneItem> questRewards = null;
        private LoopScrollAdapter<UIN_QuestCell> questCells = null;
        private LoopScrollAdapter<UIN_QuestTarget> questTargets = null;
        private UIN_CostMoney costMoney = null;

        private int indexSelectedTab = -1;
        private List<UD_OneQuest> dataList = new(4);
        private UD_OneQuest selectedQuestData = null;
        private List<int> selectedQuestDataTargets = ListPool<int>.Get();
        private int compareCid = 0;

        protected UIB_UIQuest ui { get; set; }
        protected UIMsgDispatcher uiMsgDispatcher => this._msgDispatcher as UIMsgDispatcher;

        #endregion

        protected override void BeforeInit()
        {
            ui = new UIB_UIQuest();
            ui.InitBinding(this.csObjBind);
        }

        protected override void OnInit()
        {
            this.tabs = this.InitListScroll<UIN_QuestTab>(this.ui.toggleTab, this.OnTabChanged);
            this.tabs.InitUnitSelected(new ListUnitSelect<UIN_QuestTab>.UnitSelectData()
            {
                selectedType = UnitSelectType.ByExToggle,
                callSelected = this.OnTabSelected,
                callCheckIsCanSelected = this.CheckTabIsCanSelected,
            });
            this.questCells = this.InitLoopScroll<UIN_QuestCell>(this.ui.loopVerticalScrollRect, this.OnQuestCellChanged);
            this.questCells.InitUnitSelected(UnitSelectType.ByExToggle, this.OnQuestCellSelected);

            this.questTargets = this.InitLoopScroll<UIN_QuestTarget>(this.ui.targetScroll, this.OnTargetChanged);

            #region quest details 任务详情

            this.questRewards = this.InitListScroll<UIN_OneItem>(this.ui.commonItem, this.OnRewardChanged);
            this.costMoney = this.InitChildNode<UIN_CostMoney>(this.ui.costMoney);
            this.ui.btnConfirm.onClick.AddListener(this.OnClickBtnQuestSure);
            this.ui.btnTrack.onClick.AddListener(this.OnClickBtnTrack);
            this.ui.btnCacelTrack.onClick.AddListener(this.OnClickBtnCancelTrack);

            #endregion

            this.costMoney.Hide();
            this.SetEmptyActive(false);

            var topLeftBack = this.InitChildNode<UIN_TopLeftBack>(this.ui.topLeftBack);
            topLeftBack.Show();
        }

        protected override void OnShow(UIBaseData data)
        {
            this.ShowTab();
        }

        protected override void OnHide()
        {

        }

        protected override void AddMsgListeners()
        {
            uiMsgDispatcher.AddListener<int>(MsgEventType.QuestStartTrack, OnQuestStartTrack);
        }

        private void OnQuestStartTrack(int questCid)
        {
            ShowDetails(selectedQuestData);
        }

        protected override void OnDispose()
        {
            this.indexSelectedTab = -1;
            this.selectedQuestData = null;
            this.compareCid = 0;
            if (selectedQuestDataTargets != null)
                ListPool<int>.Put(selectedQuestDataTargets);
            selectedQuestDataTargets = null;

            this.ClearDataList();
        }

        private void SetEmptyActive(bool emptyActive)
        {
            this.ui.empty.SetActive(emptyActive);
            this.ui.panelInfo.SetActive(!emptyActive);
        }

        private void ShowTab()
        {
            this.tabs.RefillCells(APIUIQuest.Tabs.Length, GetCurrentTabIndex());
        }

        private int GetCurrentTabIndex()
        {
            return Mathf.Clamp(this.indexSelectedTab, 0, APIUIQuest.Tabs.Length - 1);
        }

        private void OnTabChanged(UIN_QuestTab item, int index)
        {
            item.Show(index);
        }

        private void OnTabSelected(int index, UIN_QuestTab item)
        {
            this.indexSelectedTab = index;
            this.ShowList(item);
        }

        private bool CheckTabIsCanSelected(int index)
        {
            var type = (UIQuestTabType)APIUIQuest.Tabs[index];
            var functionType = FunctionConverts.ConvertByUIQuestTabType(type);
            return FunctionModule.CheckIsOpenAndTip(functionType);
        }

        private void ShowList(UIN_QuestTab tab = null)
        {
            if (tab == null)
                tab = this.tabs.GetTEntity(this.indexSelectedTab);
            int tabIndex = tab.tabIndex;
            this.InitDataList(tabIndex);

            int cnt = this.dataList.Count;
            int compareCid = this.compareCid;
            this.compareCid = 0;
            int _itemIndex = this.GetSelectedDataIndex(compareCid);
            this.questCells.RefillCellsAndSelected(cnt, _itemIndex);
            this.SetEmptyActive(cnt == 0);
        }

        private int GetSelectedDataIndex(int compareCid)
        {
            if (compareCid > 0 && this.dataList.Count > 0)
            {
                for (int i = 0, cnt = this.dataList.Count; i < cnt; i++)
                {
                    var itemData = this.dataList[i];
                    if (itemData.cid == compareCid)
                    {
                        return i;
                    }
                }
            }

            return 0;
        }

        private void ClearDataList()
        {
            foreach (var item in this.dataList)
            {
                item.Put2Pool();
            }

            this.dataList.Clear();
        }

        private void AddOneData(int cid, int tabIndex, bool isCommited = false)
        {
            var cfg = TableCenter.quest.Get(cid);
            if (cfg == null || cfg.IsHide || cfg.ParentQuest > 0)
                return;

            if (isCommited && !cfg.CommitedIsShow)
                return;

            var tabTypes = APIUIQuest.TabTypes[tabIndex];
            int tabLength = tabTypes?.Length ?? 0;
            bool isInTab = false;
            if (tabLength > 0 && tabLength % 2 == 0)
            {
                for (int i = 0; i < tabLength; i += 2)
                {
                    if ((int)cfg.Type == tabTypes[i] && (tabTypes[i + 1] == 0 || tabTypes[i + 1] == cfg.SubType))
                    {
                        isInTab = true;
                        break;
                    }
                }
            }

            if (!isInTab)
                return;

            UD_OneQuest itemB = UD_OneQuest.NewFromPool().Sync(cid);
            this.dataList.Add(itemB);
        }

        private void InitDataList(int tabIndex)
        {
            this.ClearDataList();
            var moduleData = GameDataCenter.PlayerData.quest;

            if (moduleData != null)
            {
                foreach (var cid in moduleData.keyInProgress)
                {
                    AddOneData(cid, tabIndex);
                }

                foreach (var cid in moduleData.keyInSuccess)
                {
                    AddOneData(cid, tabIndex, true);
                }

                if (this.dataList.Count > 1)
                    this.dataList.Sort(this.SortDataList);
            }
        }

        private int SortDataList(UD_OneQuest a, UD_OneQuest b)
        {
            bool isTrackingA = a.isTracking;
            bool isTrackingB = b.isTracking;
            if (isTrackingA != isTrackingB)
                return isTrackingA ? -1 : 1;

            bool isCanCommitA = a.isCanCommit;
            bool isCanCommitB = b.isCanCommit;
            if (isCanCommitA != isCanCommitB)
                return isCanCommitA ? -1 : 1;

            bool isSuccessA = a.isInSuccess;
            bool isSuccessB = b.isInSuccess;
            if (isSuccessA != isSuccessB)
                return isSuccessA ? 1 : -1;
            var cfgA = a.cfgData;
            var cfgB = b.cfgData;
            if (cfgA.SortOrder != cfgB.SortOrder)
                return cfgA.SortOrder < cfgB.SortOrder ? -1 : 1;
            return a.cid > b.cid ? -1 : 1;
        }

        private void OnQuestCellChanged(UIN_QuestCell cell, int index)
        {
            var data = this.GetOneQuestData(index);
            cell.Show(data);
        }

        private UD_OneQuest GetOneQuestData(int index)
        {
            return index >= 0 && index < this.dataList.Count ? this.dataList[index] : null;
        }

        private void OnQuestCellSelected(int index, UIN_QuestCell cell)
        {
            var data = this.GetOneQuestData(index);
            this.ShowDetails(data);
        }

        private void ShowDetails(UD_OneQuest udQuest)
        {
            this.selectedQuestData = null;
            selectedQuestDataTargets.Clear();
            if (udQuest == null)
                return;
            this.selectedQuestData = udQuest;


            var cfgQuest = udQuest.cfgData;
            this.ui.textName.text = cfgQuest.Name;
            this.ui.textDesc.text = cfgQuest.Description;
            this.ReInitDetailTargets();
            this.ShowDetailsTarget();
            this.ShowDetailsLocationMap();
            this.ShowDetailsRewards();
            this.ShowDetailsCostMoney();
            this.ShowDetailsOperateBtn();
            this.ShowDetailsBtnTrack();
            this.ShowDetailsBtnCancelTrack();
        }

        private void ReInitDetailTargets()
        {
            var list = this.selectedQuestData.cfgData.ChildQuests;
            if (list.Count == 0)
            {
                selectedQuestDataTargets.Add(this.selectedQuestData.cid);
                return;
            }
            var quest = GameDataCenter.PlayerData.quest;
            for (int i = 0; i < list.Count; i++)
            {
                if (quest.IsInSuccess(list[i]) || quest.ContainsKey(list[i]))
                    selectedQuestDataTargets.Add(list[i]);
            }
        }

        private int GetActiveTargetCid()
        {
            var quest = GameDataCenter.PlayerData.quest;
            for (int i = 0; i < selectedQuestDataTargets.Count; i++)
            {
                if (quest.ContainsKey(selectedQuestDataTargets[i]))
                    return selectedQuestDataTargets[i];
            }
            return selectedQuestDataTargets[0];
        }

        private void ShowDetailsTarget()
        {
            var list = this.selectedQuestDataTargets;
            int cnt = Math.Max(list.Count, 1);
            this.questTargets.RefillCells(cnt);
        }

        private void OnTargetChanged(UIN_QuestTarget item, int index)
        {
            var list = this.selectedQuestDataTargets;
            item.Show(list[index], GetTargetProgress(list[index]));
        }

        private int GetTargetProgress(int questCid)
        {
            var cfg = TableCenter.quest.Get(questCid);
            if (cfg == null)
                return 0;

            var questState = this.selectedQuestData.GetQuestState(questCid);
            GameDataCenter.PlayerData.quest.TryGetValue(questCid, out var quest);
            return questState switch
            {
                QuestState.Activating => Math.Min(quest.progress, cfg.TargetNum),
                QuestState.Success => cfg.TargetNum,
                _ => 0,
            };
        }

        private void ShowDetailsLocationMap()
        {
            CfgQuest cfgQuest = this.selectedQuestData.cfgData;
            bool isActive = (cfgQuest.TargetRegion > 0);
            if (isActive)
            {
                var cfgRegion = TableCenter.regionInstance.Get(cfgQuest.TargetRegion);
                isActive = (cfgRegion != null);

                if (isActive)
                {
                    this.ui.textLocation.text = cfgRegion.Name;
                }
            }

            this.ui.location.SetActive(isActive);
            this.ui.locationValue.SetActive(isActive);
        }

        private void ShowDetailsRewards()
        {
            CfgQuest cfgQuest = this.selectedQuestData.cfgData;
            int cntRwd = cfgQuest.Reward.Count / APIUIConst.RewardDefaultSpacing;
            this.questRewards.RefillCells(cntRwd);
        }

        private void ShowDetailsCostMoney()
        {
            UD_OneQuest udQuest = this.selectedQuestData;
            CfgQuest cfgQuest = udQuest.cfgData;
            if (!udQuest.isCanCommit || cfgQuest.CommitCostItem.Count == 0)
            {
                this.costMoney.Hide();
            }
            else
            {
                this.costMoney.Show(cfgQuest.CommitCostItem[0], cfgQuest.CommitCostItem[1]);
            }
        }

        private void ShowDetailsOperateBtn()
        {
            UD_OneQuest udQuest = this.selectedQuestData;
            CfgQuest cfgQuest = udQuest.cfgData;
            bool isActive = false;
            if (udQuest.isActivating)
            {
                isActive = (cfgQuest.TargetRegion > 0 && udQuest.isTracking) || cfgQuest.Source > 0;
            }
            else if (udQuest.isCanCommit)
            {
                isActive = true;
            }

            if (isActive)
                this.ui.btnConfirm.text = APIUIQuest.GetBtnByQuestState(udQuest.questState);
            this.ui.btnConfirm.SetActive(isActive);
        }


        private void ShowDetailsBtnTrack()
        {
            bool isActive = this.selectedQuestData.isCanTrack;
            this.ui.btnTrack.SetActive(isActive);
        }

        private void ShowDetailsBtnCancelTrack()
        {
            bool isActive = this.selectedQuestData.isTracking;
            this.ui.btnCacelTrack.SetActive(isActive);
        }

        private void OnRewardChanged(UIN_OneItem item, int index)
        {
            var cfg = this.selectedQuestData.cfgData;
            var rwds = cfg.Reward;
            var indexStart = index * APIUIConst.RewardDefaultSpacing;
            item.Show(rwds[indexStart], rwds[indexStart + 1]);
        }

        private void OnClickBtnQuestSure()
        {
            if (this.selectedQuestData.isActivating)
            {
                this.OnClickGotoTarget();
            }
            else if (this.selectedQuestData.isCanCommit)
            {
                this.SendCommitCurrentQuest();
            }
        }

        private void OnClickGotoTarget()
        {
            var questCid = GetActiveTargetCid();
            var cfgData = TableCenter.quest.Get(questCid);
            if (cfgData.TargetRegion == 0)
            {
                // TODO 界面打开逻辑？？？
            }
            else
            {
                GoToMap(questCid).Forget();
            }
        }

        private async UniTaskVoid GoToMap(int questCid)
        {
            if (questCid <= 0)
                return;

            if (!FunctionModule.CheckIsOpenAndTip(FunctionType.Map) || !FunctionModule.CheckIsOpenAndTip(FunctionType.MapTransmit))
                return;

            var canGotoMap = await UILevelMap.TryGoto(questCid);
            if (canGotoMap)
            {
                Close();
            }
        }

        private void SendCommitCurrentQuest()
        {
            if (!this.costMoney.CheckIsEnough())
            {
                return;
            }

            this.SendCommitQuests(this.selectedQuestData.cid, false).Forget();
        }

        private async UniTaskVoid SendCommitQuests(int cid, bool isBatch)
        {
            List<int> list = ListPool<int>.Get();
            list.Add(cid);
            var result = await QuestModule.NetCore.CS_commitQuest(list, isBatch);
            ListPool<int>.Put(list);
            if (result.IsSuccess)
            {
                int commintCid = isBatch ? 0 : cid;
                this.RefreshAfterCommitResponse(commintCid);
            }
        }

        private void RefreshAfterCommitResponse(int commintCid)
        {
            if (commintCid > 0)
            {
                int _itemIndex = this.GetSelectedDataIndex(commintCid) - 1;
                if (_itemIndex >= 0)
                {
                    this.compareCid = this.dataList[_itemIndex].cid;
                }
            }

            this.ShowList();
        }

        private void OnClickBtnTrack()
        {
            int cid = this.GetActiveTargetCid();
            this.SendTrackQuest(cid).Forget();
        }

        private async UniTaskVoid SendTrackQuest(int questCid)
        {
            var result = await QuestModule.NetCore.CS_setTrackQuest(questCid);
            if (result.IsSuccess)
            {
                this.RefreshAfterTrackResponse();
                GoToMap(questCid).Forget();
            }
        }

        private void RefreshAfterTrackResponse()
        {
            this.questCells.RefreshCells();
        }

        private void OnClickBtnCancelTrack()
        {
            this.SendTrackQuest(0).Forget();
        }
    }
}
